/**
 * 惰性执行，去抖动
 * 函数在被调用fps秒才会被执行，如果中间被打断，则继续向后顺延fps秒
 * @param {function} fn
 * @param {number} [fps=60]
 * @returns {function}
 */
export function debounce(fn, fps = 60) {
    let ST = null;
    return (...args) => {
        if (fps > 0) {
            clearTimeout(ST);
            ST = setTimeout(() => {
                fn(...args);
            }, fps);
        } else {
            fn(...args);
        }
    };
}

/**
 * 事件被第一次触发后，立即执行，当过了fps后才能再次响应执行
 * @param {function} fn
 * @param {number} [fps=60]
 * @returns {function}
 */
export function throttle(fn, fps = 60) {
    let disabled = false;

    return (...args) => {
        if (!disabled) {
            disabled = true;
            fn(...args);

            setTimeout(() => {
                disabled = false;
            }, fps);
        }
    };
}

/**
 * 以某个频率做某件事情，且第一次、最后一次调用必然会被触发
 * @param {function} fn
 * @param {number} [fps=60]
 * @returns {function}
 */
export function frequency(fn, fps = 60) {
    let time = 0;
    let now = time;
    let ST;
    const newFn = (...args) => {
        clearTimeout(ST);
        now = Date.now();
        const distance = now - time;

        if (distance >= fps) {
            time = now;
            fn(...args);
        } else {
            ST = setTimeout(() => {
                newFn(...args);
            }, distance);
        }
    };
    return newFn;
}

// 事件参数persist
function _persistEvent(args) {
    args.forEach(it => {
        if (it.isPersistent && it.isPersistent()) return;
        it.persist && $.isFunction(it.persist) && it.persist();
    });
}

// 公共函数封装
function _commonHandler(handler) {
    return function (target, name, descriptor) {
        if (descriptor.initializer) {
            return {
                enumerable: false,
                configurable: true,
                get() {
                    return handler(descriptor.initializer.call(this));
                },
            };
        }

        if (!descriptor || (arguments.length === 1 && typeof target === 'function')) {
            console.error('请在类成员函数上使用');
            return handler(target);
        }

        return {
            ...descriptor,
            writable: false,
            value: handler(descriptor.value),
        };
    };
}

// 装饰器版本，函数在被调用fps秒才会被执行，如果期间再次调用，则继续向后顺延fps秒
export function Debounce(delay) {
    let timer = null;
    return _commonHandler((fn) => function (...args) {
        _persistEvent(args);
        timer && clearTimeout(timer);

        timer = setTimeout(() => {
            fn.apply(this, args);
            timer = null;
        }, delay);
    });
}

// 装饰器版本，事件被第一次触发后，立即执行，当过了fps后才能再次响应执行
export function Throttle(fps) {
    let disabled = false;
    return _commonHandler((fn) => function (...args) {
        _persistEvent(args);
        if (!disabled) {
            disabled = true;
            fn.apply(this, args);

            setTimeout(() => {
                disabled = false;
            }, fps);
        }
    });
}

// 装饰器版本，以某个频率做某件事情，且第一次、最后一次调用必然会被触发
export function Frequency(fps = 100) {
    let time = 0;
    let now = time;
    let ST;
    return _commonHandler((fn) => {
        function newFn(...args) {
            _persistEvent(args);
            clearTimeout(ST);
            now = Date.now();
            const distance = now - time;

            if (distance >= fps) {
                time = now;
                fn.apply(this, args);
            } else {
                ST = setTimeout(() => {
                    newFn(...args);
                }, distance);
            }
        }
        return newFn;
    });
}
